<script setup lang="ts">
  import { useTypingStore } from '@renderer/store'
  import { pinyin } from 'pinyin-pro'
  import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue'

  const typingStore = useTypingStore()

  // 状态变量
  const inputRefs = ref<HTMLInputElement[]>([])
  const wordRefs = ref<HTMLElement[]>([])
  const containerRef = ref<HTMLElement | null>(null)
  const ignoreNextInput = ref(false) // 是否忽略下一次输入，用于暂停恢复后防止按键被记录
  const prevInputValues = ref<string[]>([]) // 保存上一次的输入值，用于检测错误

  // 初始化词语列表
  const initializeWords = () => {
    // 初始化词语列表
    typingStore.initWords()
    // 初始化上一次输入值数组
    prevInputValues.value = Array(typingStore.words.length).fill('')

    // 聚焦第一个输入框
    nextTick(() => {
      focusInput(0)
    })
  }

  // 计算每个词的拼音
  const wordPinyinList = computed(() => {
    return typingStore.words.map((word) => {
      // 获取不带声调的拼音，v模式会自动将ü转为v
      const pinyinText = pinyin(word, {
        toneType: 'none',
        v: true, // 使用v代替ü
        type: 'array'
      })
        .join('')
        .replace(/\s/g, '')

      return pinyinText
    })
  })

  // 判断词的输入是否有错误
  const hasError = (index: number) => {
    // 如果索引无效，返回false
    if (index < 0 || index >= typingStore.inputs.length) {
      return false
    }

    const input = typingStore.inputs[index]
    const pinyin = wordPinyinList.value[index]

    // 如果输入为空，并且不是当前输入的词，视为错误
    if (input.length === 0 && index < typingStore.currentIndex) {
      return true
    }

    // 如果输入长度与拼音长度不一致，有错误
    if (input.length !== pinyin.length && index < typingStore.currentIndex) {
      return true
    }

    // 检查每个字符是否正确
    for (let i = 0; i < input.length; i++) {
      if (input[i] !== pinyin[i]) {
        return true
      }
    }

    return false
  }

  // 计算单个词的错误字符数
  const countWordErrors = (index: number) => {
    const input = typingStore.inputs[index] || ''
    const pinyin = wordPinyinList.value[index] || ''
    let errorCount = 0

    // 检查已输入的字符
    for (let i = 0; i < Math.min(input.length, pinyin.length); i++) {
      if (input[i] !== pinyin[i]) {
        errorCount++
      }
    }

    // 如果输入长度小于拼音长度，且是已完成的词，差值也算错误
    if (index < typingStore.currentIndex && input.length < pinyin.length) {
      errorCount += pinyin.length - input.length
    }

    // 如果输入长度大于拼音长度，多余字符也算错误
    if (input.length > pinyin.length) {
      errorCount += input.length - pinyin.length
    }

    return errorCount
  }

  // 计算所有已输入词的错误总数，包括修正的错误（包括用户修改过的错误和当前存在的错误）
  const calculateTotalErrors = () => {
    let totalErrors = 0
    for (let i = 0; i <= typingStore.currentIndex; i++) {
      if (i < typingStore.inputs.length) {
        totalErrors += countWordErrors(i)
      }
    }
    return totalErrors
  }

  // 检查输入变化是否包含错误
  const checkForErrors = (index: number, newValue: string) => {
    const prevValue = prevInputValues.value[index] || ''
    const expectedPinyin = wordPinyinList.value[index]

    // 如果新输入比之前长，检查新添加的字符是否错误
    if (newValue.length > prevValue.length) {
      const lastChar = newValue[newValue.length - 1]
      const expectedChar = expectedPinyin[newValue.length - 1]

      // 如果输入的字符与预期不同，或超出了拼音长度
      if (
        newValue.length > expectedPinyin.length ||
        (expectedChar !== undefined && lastChar !== expectedChar)
      ) {
        // 记录一次错误输入
        typingStore.incrementTotalErrorCount()
      }
    }

    // 更新上一次的输入值
    prevInputValues.value[index] = newValue
  }

  // 设置是否忽略下一次输入
  const setIgnoreNextInput = (value: boolean) => {
    ignoreNextInput.value = value
  }

  // 处理输入
  const handleInput = (index: number, e: Event) => {
    // 如果需要忽略这次输入，则重置标志并返回
    if (ignoreNextInput.value) {
      ignoreNextInput.value = false
      return
    }

    // 确保首次输入时正确启动计时器
    typingStore.startTimer()

    // 只处理当前活动的输入框
    if (index === typingStore.currentIndex) {
      const input = e.target as HTMLInputElement
      const newValue = input.value

      // 检查输入是否有错误
      checkForErrors(index, newValue)

      // 更新输入值
      typingStore.inputs[index] = newValue

      // 重新计算总输入字符数（包含正确和错误的字符）
      // 不能只累加差值，因为用户可能删除了字符
      typingStore.totalTypedChars = 0
      for (let i = 0; i <= typingStore.currentIndex; i++) {
        if (typingStore.inputs[i]) {
          typingStore.totalTypedChars += typingStore.inputs[i].length
        }
      }

      // 更新错误字符数
      typingStore.totalErrorChars = calculateTotalErrors()

      // 每次输入都确保活动词在可视区域中间
      scrollToActiveWord()
    }
  }

  // 处理按键
  const handleKeyDown = (index: number, e: KeyboardEvent) => {
    // 只处理当前活动的输入框
    if (index !== typingStore.currentIndex || typingStore.isPaused) {
      e.preventDefault()
      return
    }

    // 空格键处理
    if (e.key === ' ' || e.code === 'Space') {
      e.preventDefault() // 阻止空格输入

      // 如果不是最后一个输入框并且当前输入框有输入，跳到下一个
      if (index < typingStore.words.length - 1 && typingStore.inputs[index].length > 0) {
        typingStore.currentIndex = index + 1
        focusInput(index + 1)
      } else if (index === typingStore.words.length - 1) {
        // 如果是最后一个词，标记为完成
        typingStore.completed()
      }
    }

    // 退格键处理
    else if (e.key === 'Backspace') {
      // 如果当前输入框为空且不是第一个输入框
      if (typingStore.inputs[index].length === 0 && index > 0) {
        // 上一个词有错误时，允许退格到上一个词
        const prevWordIndex = index - 1
        const prevWordHasError = prevWordIndex >= 0 && hasError(prevWordIndex)
        if (prevWordHasError) {
          typingStore.currentIndex = prevWordIndex
          focusInput(prevWordIndex)
          e.preventDefault()
          return
        }
      }
    }
  }

  // 阻止点击选择输入框
  const handleFocus = (index: number, e: FocusEvent) => {
    // 如果不是当前活动的输入框，阻止聚焦并重新聚焦到当前活动输入框
    if (index !== typingStore.currentIndex) {
      e.preventDefault()
      e.stopPropagation()
      focusInput(typingStore.currentIndex)
    }
  }

  // 全局点击处理，始终聚焦到当前活动输入框
  const handleContainerClick = () => {
    focusInput(typingStore.currentIndex)
  }

  // 禁用滚轮滚动
  const disableWheel = (e: WheelEvent) => {
    e.preventDefault()
    e.stopPropagation()
    return false
  }

  // 获取字符样式
  const getCharClass = (wordIndex: number, charIndex: number) => {
    const input = typingStore.inputs[wordIndex]
    const pinyinLength = wordPinyinList.value[wordIndex].length

    // 如果已经输入了这个位置
    if (charIndex < input.length) {
      // 如果这个位置是超出拼音长度的部分
      if (charIndex >= pinyinLength) {
        // 超出部分显示为红色
        return 'text-red-400'
      }

      const expectedChar = wordPinyinList.value[wordIndex][charIndex]
      const actualChar = input[charIndex]

      // 如果输入正确，显示白色
      if (actualChar === expectedChar) {
        return 'dark:text-white text-black'
      } else {
        // 输入错误，显示红色
        return 'text-red-400'
      }
    }

    // 未输入的字符显示灰色
    return 'text-gray-400'
  }

  // 获取需要显示的字符
  const getDisplayChar = (wordIndex: number, charIndex: number) => {
    const pinyinText = wordPinyinList.value[wordIndex]
    // 检查inputs是否初始化
    const input = typingStore.inputs[wordIndex] || ''
    const pinyinLength = pinyinText.length

    // 如果是拼音范围内的字符
    if (charIndex < pinyinLength) {
      return pinyinText[charIndex]
    }
    // 如果是用户输入的超出部分
    else if (charIndex >= pinyinLength && charIndex < input.length) {
      return input[charIndex]
    }

    return ''
  }

  // 获取要显示的字符数组（包含拼音字符和超出输入）
  const getDisplayChars = (wordIndex: number) => {
    const pinyinText = wordPinyinList.value[wordIndex]
    const input = typingStore.inputs[wordIndex] || ''

    // 取拼音长度和输入长度的较大值作为显示字符的总长度
    const displayLength = Math.max(pinyinText.length, input.length)

    // 创建一个长度为displayLength的数组
    return Array.from({ length: displayLength }, (_, i) => i)
  }

  // 聚焦输入框
  const focusInput = (index: number) => {
    nextTick(() => {
      if (inputRefs.value[index]) {
        inputRefs.value[index].focus()
        scrollToActiveWord()
      }
    })
  }

  // 滚动到当前活动的词
  const scrollToActiveWord = () => {
    nextTick(() => {
      if (wordRefs.value[typingStore.currentIndex] && containerRef.value) {
        const wordElement = wordRefs.value[typingStore.currentIndex]
        const containerElement = containerRef.value

        // 计算当前词到容器顶部的距离
        const wordTop = wordElement.offsetTop
        const wordHeight = wordElement.offsetHeight
        const containerHeight = containerElement.offsetHeight

        // 滚动位置：让当前词在容器中间
        const targetScrollTop = wordTop - containerHeight / 2 + wordHeight / 2

        // 平滑滚动到目标位置
        containerElement.scrollTo({
          top: targetScrollTop,
          behavior: 'smooth'
        })
      }
    })
  }

  // 设置引用
  const setInputRef = (el: HTMLInputElement, index: number) => {
    if (el) {
      inputRefs.value[index] = el
    }
  }

  // 设置词元素引用
  const setWordRef = (el: HTMLElement, index: number) => {
    if (el) {
      wordRefs.value[index] = el
    }
  }

  // 判断是否显示下划线
  const showUnderline = (wordIndex: number) => {
    return wordIndex === typingStore.currentIndex
  }

  // 监听当前索引变化，自动滚动
  watch(
    () => typingStore.currentIndex,
    () => {
      scrollToActiveWord()

      // 更新错误计数
      typingStore.totalErrorChars = calculateTotalErrors()
    }
  )

  // 向外暴露方法
  // 聚焦当前输入框的方法，供外部调用
  const focusCurrentInput = () => {
    focusInput(typingStore.currentIndex)
  }

  // 向外暴露方法
  defineExpose({
    focusCurrentInput,
    setIgnoreNextInput
  })

  onMounted(() => {
    // 然后再初始化词语
    initializeWords()

    // 初始化后立即滚动到第一个词
    nextTick(() => {
      scrollToActiveWord()
    })

    // 添加滚轮事件监听
    if (containerRef.value) {
      containerRef.value.addEventListener('wheel', disableWheel, { passive: false })

      // 添加滚动事件监听，确保滚动后活动词仍然在中间位置
      containerRef.value.addEventListener(
        'scroll',
        () => {
          // 使用requestAnimationFrame降低滚动监听的频率
          requestAnimationFrame(() => {
            if (!containerRef.value?.scrollTop) return
            scrollToActiveWord()
          })
        },
        { passive: true }
      )
    }
  })

  onUnmounted(() => {
    // 移除滚轮事件监听
    if (containerRef.value) {
      containerRef.value.removeEventListener('wheel', disableWheel)
    }
  })
</script>

<template>
  <div
    class="p-5 scroll-smooth max-h-76 min-h-200px relative overflow-auto"
    style="-ms-overflow-style: none; scrollbar-width: none"
    @click="handleContainerClick"
    @wheel.prevent
    ref="containerRef"
  >
    <div class="flex flex-wrap gap-4">
      <div
        v-for="(chineseWord, wordIndex) in typingStore.words"
        :key="wordIndex"
        class="mb-4 flex flex-col gap-1 min-h-12 transition-all duration-300 items-center"
        :class="[
          wordIndex < typingStore.currentIndex && hasError(wordIndex) ? 'completed-error' : ''
        ]"
        :ref="(el) => setWordRef(el as HTMLElement, wordIndex)"
      >
        <span
          class="text-xl transition-colors duration-300 text-app"
          :class="{
            'text-red-400 font-bold': wordIndex < typingStore.currentIndex && hasError(wordIndex)
          }"
        >
          {{ chineseWord }}
        </span>
        <div
          class="flex flex-row relative"
          :class="{ 'border-b-2 border-indigo-400': showUnderline(wordIndex) }"
        >
          <span
            v-for="(_char, charIndex) in getDisplayChars(wordIndex)"
            :key="charIndex"
            class="text-2xl font-semibold tracking-normal font-mono"
            :class="getCharClass(wordIndex, charIndex)"
          >
            {{ getDisplayChar(wordIndex, charIndex) }}
          </span>

          <input
            :ref="(el) => setInputRef(el as HTMLInputElement, wordIndex)"
            type="text"
            class="outline-none border-none bg-transparent opacity-0 h-full w-full cursor-text select-none inset-0 absolute z-1"
            :class="{ 'rounded-md shadow-indigo': wordIndex === typingStore.currentIndex }"
            style="user-select: none; -webkit-user-drag: none"
            :value="typingStore.inputs[wordIndex] || ''"
            @input="handleInput(wordIndex, $event)"
            @keydown="handleKeyDown(wordIndex, $event)"
            @focus="handleFocus(wordIndex, $event)"
          />
        </div>
      </div>
    </div>
  </div>
</template>
